package com.xiaohe66.demo.spring.slp;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ServiceLocatorFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Service Locator Pattern
 * Spring 服务定位模式
 * <p>
 * 类似于策略模式，但可以依赖于 Spring，使实现更加优雅
 * 1. 定义一个操作的接口 {@link com.xiaohe66.demo.spring.slp.Animal}，用于统一行为。相同行为的不同动作都实现这个接口
 * 2. 定义一个接口工厂 {@link com.xiaohe66.demo.spring.slp.AnimalFactory}，并提供获取实例的方法
 * 3. 向 Spring 注册这个工厂 {@link ServiceLocatorPatternMain#animalFactory()}
 *
 * @author xiaohe
 * @since 2023.02.10 13:41
 */
@Configuration
@ComponentScan(basePackageClasses = ServiceLocatorPatternMain.class)
public class ServiceLocatorPatternMain {

    /**
     * 这个工厂Bean最终实例化的是一个 JDK 的代理对象，在这个方法实例化的 {@link ServiceLocatorFactoryBean#afterPropertiesSet()}
     */
    @Bean
    public FactoryBean<Object> animalFactory() {

        ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
        // 设置为工厂的接口
        factoryBean.setServiceLocatorInterface(AnimalFactory.class);

        return factoryBean;
    }

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(ServiceLocatorPatternMain.class);
        context.refresh();

        AnimalFactory animalFactory = context.getBean(AnimalFactory.class);

        Animal cat = animalFactory.getInstance("cat");
        cat.say();

        Animal dog = animalFactory.getInstance("dog");
        dog.say();

    }
}
